package com.szbmyoubao.app.helper

import com.szbmyoubao.app.http.RetrofitClient
import com.szbmyoubao.app.view.dialog.DownloadState
import com.ellecity06.common.utils.FileUtil
import com.ellecity06.common.utils.logD
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch

import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn

import okhttp3.ResponseBody
import okio.IOException
import java.io.File
import java.io.FileOutputStream
import java.io.OutputStream

/**
 * 下载管理
 */
class DownloadManager {
    companion object {

        /**
         * 下载 ，
         * @param file 保存的文件
         */
        suspend fun download(url: String, file: File): Flow<DownloadState> {
            return flow {
                val response = RetrofitClient.downloadService.download(url)
                if (response.isSuccessful) {
                    saveToFile(response.body()!!, file) {
                        emit(DownloadState.InProgress(it))
                    }
                    emit(DownloadState.Success(file))
                } else {
                    emit(DownloadState.Error(IOException(response.toString())))
                }
            }.catch {
                emit(DownloadState.Error(it))
            }.flowOn(Dispatchers.IO)
        }

        suspend fun download(url: String): Flow<DownloadState> {
            return flow {
                val response = RetrofitClient.downloadService.download(url)
                var fileName = url.substring(url.lastIndexOf("/") + 1)
                if (fileName.contains("?")) {
                    fileName = fileName.substring(0, fileName.indexOf("?"))
                }
                logD("fileName=${fileName}")
                val file = File(FileUtil.defaultCacheFileDir, fileName)
                if (response.isSuccessful) {
                    saveImage(response.body()!!, file) {
                        emit(DownloadState.InProgress(it))
                    }
                    emit(DownloadState.Success(file))
                } else {
                    emit(DownloadState.Error(IOException(response.toString())))
                }
            }.catch {
                emit(DownloadState.Error(it))
            }.flowOn(Dispatchers.IO)
        }

        suspend fun download(list: List<String>): Flow<DownloadState> {
            return flow {
                list.forEach { url ->
                    logD("url=${url}")
                    val response = RetrofitClient.downloadService.download(url)
                    var fileName = url.substring(url.lastIndexOf("/") + 1)
                    if (fileName.contains("?")) {
                        fileName = fileName.substring(0, fileName.indexOf("?"))
                    }
                    val file = File(FileUtil.defaultCacheFileDir, fileName)
                    logD("下载图片=${file.absolutePath}")
                    if (response.isSuccessful) {
                        saveImage(response.body()!!, file) {
                            emit(DownloadState.InProgress(it))
                        }
                        emit(DownloadState.Success(file))
                    } else {
                        emit(DownloadState.Error(IOException(response.toString())))
                    }
                }
            }.catch {
                logD("", tr = it)
                emit(DownloadState.Error(it))
            }.flowOn(Dispatchers.IO)
        }


        private inline fun saveToFile(
            responseBody: ResponseBody,
            file: File,
            progressListener: (Int) -> Unit
        ) {
            if (file.exists()) file.delete()
            val `is` = responseBody.byteStream()
            val length = responseBody.contentLength()
            val os: OutputStream = FileOutputStream(file)
            val bs = ByteArray(1024 * 2)
            var len: Int
            var count: Long = 0
            while (`is`.read(bs).also { len = it } != -1) {
                count += len.toLong()
                os.write(bs, 0, len)
                progressListener.invoke((count * 100 / length).toInt())
            }
            `is`.close()
            os.close()
        }

        inline fun saveImage(
            responseBody: ResponseBody,
            file: File,
            progressListener: (Int) -> Unit
        ) {
            if (!file.parentFile.exists()) {
                file.parentFile.mkdirs()
            }
            if (file.exists()) {
                progressListener.invoke(100)
                return
            }
            val `is` = responseBody.byteStream()
            val length = responseBody.contentLength()
            val os: OutputStream = FileOutputStream(file)
            val bs = ByteArray(1024 * 2)
            var len: Int
            var count: Long = 0
            while (`is`.read(bs).also { len = it } != -1) {
                count += len.toLong()
                os.write(bs, 0, len)
                progressListener.invoke((count * 100 / length).toInt())
            }
            `is`.close()
            os.close()
        }

    }
}
